package com.bacon.gmall.activity.listener;

import cn.hutool.core.date.DateUtil;
import com.bacon.gmall.activity.mapper.SeckillMapper;
import com.bacon.gmall.activity.utils.CacheHelper;
import com.bacon.gmall.common.config.RabbitConst;
import com.bacon.gmall.common.constant.RedisConst;
import com.bacon.gmall.model.activity.SeckillGoods;
import com.bacon.gmall.model.activity.UserRecode;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.rabbitmq.client.Channel;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.Exchange;
import org.springframework.amqp.rabbit.annotation.Queue;
import org.springframework.amqp.rabbit.annotation.QueueBinding;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;

import java.io.IOException;
import java.util.Date;
import java.util.List;

/**
 * @author： bacon、
 * @version： 1.0
 * @create： 2021-01-13 08:42
 * @description:
 */
@Component
public class SeckillConsumer {

    @Autowired
    private SeckillMapper seckillMapper;

    @Autowired
    private RedisTemplate redisTemplate;

    //秒杀之监听到MQ中消息
    @RabbitListener(bindings = {
            @QueueBinding(
                    value = @Queue(value = RabbitConst.QUEUE_SECKILL_USER,
                            durable = "true",
                            autoDelete = "false"),
                    exchange = @Exchange(value = RabbitConst.EXCHANGE_DIRECT_SECKILL_USER),
                    key = RabbitConst.ROUTING_SECKILL_USER)})
    public void receiverMessageSeckill(Message message, Channel channel, UserRecode userRecode) throws IOException {

        /**
         * 经过MQ削峰后，对数据再次进行判断，步骤如下
         * 1、判断状态位
         * 2、校验此用户是否已经买过
         * 3、校验商品库存
         *   没有 ， 更新状态位
         *   有  ，  抢购成功
         * 4、收尾工作
         */

        //1、判断状态位
        Long skuId = userRecode.getSkuId();
        String userId = userRecode.getUserId();
        String state = (String) CacheHelper.get(skuId.toString());
        if (!"1".equals(state)) {
            System.out.println("此时商品状态位表示无货");
            channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
            return;
        }
        //2、校验此用户是否已经买过
        //setIfAbsent 如果不存在就返回true ， 反之则返回false
        Boolean ifAbsent = redisTemplate.opsForValue().
                setIfAbsent(RedisConst.SECKILL_USER + userId + "skuId:" + skuId, skuId.toString());
        if (!ifAbsent) {
            System.out.println("不能重复购买");
            channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
            return;
        }


        //3、校验商品库存
        Object o = redisTemplate.opsForList().rightPop(RedisConst.SECKILL_STOCK_PREFIX + skuId);
        if (null == o) {

            //  没有 ， 更新状态位
            System.out.println("没有库存");
            redisTemplate.convertAndSend("seckillpush", skuId + ":0");
            channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
            return;
        }

        //有，抢购成功
        redisTemplate.opsForValue().set(RedisConst.SECKILL_ORDERS + userId + "skuId:" + skuId, skuId.toString());

        channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);

    }


    @RabbitListener(bindings = {
            @QueueBinding(
                    value = @Queue(value = RabbitConst.QUEUE_TASK_1,
                            durable = "true",
                            autoDelete = "false"),
                    exchange = @Exchange(value = RabbitConst.EXCHANGE_DIRECT_TASK),
                    key = {RabbitConst.ROUTING_TASK_1})})
    public void receiveMessage(Message message, Channel channel) {
        try {

            //将DB中数据库压入缓存中
            //1、查询DB中的数据库 当天的秒杀商品
            //   审核
            //   检查库存
            //2、放到缓存中
            //redisTemplate.opsForList().leftPop();
            List<SeckillGoods> seckillGoodsList = seckillMapper.selectList(new QueryWrapper<SeckillGoods>().
                    eq("status", 1).
                    gt("stock_count", 0).
                    eq("DATE_FORMAT(start_time,'%Y-%m-%d')", DateUtil.formatDate(new Date())));
            seckillGoodsList.forEach(seckillGoods -> {
                //判断是否redis有秒杀商品
                if (!redisTemplate.opsForHash().hasKey(
                        RedisConst.SECKILL_GOODS,
                        seckillGoods.getSkuId().toString())) {

                    //放入缓存中
                    redisTemplate.opsForHash().put(
                            RedisConst.SECKILL_GOODS,
                            seckillGoods.getSkuId().toString(), seckillGoods);

                    //  使用Redis防止超卖
                    String[] ids = buildSkuStock(
                            seckillGoods.getStockCount(),
                            seckillGoods.getSkuId().toString());
                    redisTemplate.opsForList().leftPushAll(
                            RedisConst.SECKILL_STOCK_PREFIX + seckillGoods.getSkuId(), ids);

                    //  状态位 ： 用于筛选请求，状态位就是判断是否还有库存
                    redisTemplate.convertAndSend(
                            "seckillpush",
                            seckillGoods.getSkuId() + ":1");
                }
            });
            //Rabbit MQ 应答
            channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private String[] buildSkuStock(Integer stockCount, String skuId) {

        String[] ids = new String[stockCount];
        for (int i = 0; i < stockCount; i++) {
            ids[i] = skuId;
        }
        return ids;
    }
}
